#include <iostream>
#include <string>
#include <utility>
using namespace std;

////////////////////////////////////////////example///1///////////////////////////////////////////////////////
// print variadic template
/*可变参数模板:
 *1.有特化版本先执行特化版本,无特化版本就执行泛化版本
 *2.参数包总是分成1+N
 */
void print() { cout << "print empty" << endl; }

template <class T> void print(const T& val) {
    cout << "print1 val:" << val << endl;
}

template <typename T, class... Types>
void print(const T& val, const Types&... args) {
    cout << "print2 val:" << val << "\t" << sizeof...(args) << endl;
    print(args...);
}

template <typename... Types> void print(const Types&... args) {
    cout << "print3 val:"
         << "\t" << sizeof...(Types) << endl;
    // print(args...);
}
////////////////////////////////////////////example///2///////////////////////////////////////////////////////

void myPrintf(const char* s) {
    while (*s) {
        if (*s == '%' && *++s != '%')
            break;
        std::cout << *s++;
    }
}
// myPrintf("%d %s %p %f\n",15,"this is ace",pi,3.45);
template <typename T, typename... Types>
void myPrintf(const char* s, T value, Types... args) {
    while (*s) {
        if (*s == '%' && *++s != '%') {
            std::cout << value;
            myPrintf(++s, args...);
            return;
        }
        if (*s == ' ')
            std::cout << *s;
        ++s;
    }
    std::cout << "test is error occurs" << endl;
}

////////////////////////////////////////////example///3///////////////////////////////////////////////////////
#include <initializer_list>
struct iter_less_cmp {
    template <typename Iter1, typename Iter2>
    bool operator()(Iter1 a, Iter2 b) const {
        return *a < *b;
    }
};

template <typename ForwardIterator, typename Compare>
inline ForwardIterator _vmax_element(ForwardIterator first,
                                     ForwardIterator last, Compare cmp) {
    ForwardIterator result = first;
    if (first == last)
        return result;
    while (++first != last) {
        if (cmp(result, first)) {
            result = first;
        }
    }

    return result;
}

template <typename ForwardIterator>
inline ForwardIterator vmax_element(ForwardIterator first,
                                    ForwardIterator last) {
    return _vmax_element(first, last, iter_less_cmp());
}

template <typename T> inline T vmax(const std::initializer_list<T>& list) {
    return *vmax_element(list.begin(), list.end());
}
////////////////////////////////////////////example///4///////////////////////////////////////////////////////
template <typename T> inline T ymax(const T& a, const T& b) {
    return a < b ? b : a;
}

template <typename T> inline T ymaximum(const T& a) { return a; }

template <typename T, typename... Types>
inline T ymaximum(const T& value, const Types&... args) {
    return ymax(value, ymaximum(args...));
}
////////////////////////////////////////////example///5///////////////////////////////////////////////////////
/*
*1.需求:使用cout打印tuple的内容,第一个内容之前用[,最后一个内容之后用],中间使用","连接
*2
  2.1:重载operator<<
*/

#include <bitset>
#include <tuple>
template <int idx, int max, typename... Args> struct MyPrintTuple {
    static void MyPrint(ostream& os, const std::tuple<Args...>& obj) {
        os << get<idx>(obj) << (idx + 1 != max ? "," : "");
        MyPrintTuple<idx + 1, max, Args...>::MyPrint(os, obj);
    }
};
template <int max, typename... Args> struct MyPrintTuple<max, max, Args...> {
    static void MyPrint(ostream& os, const std::tuple<Args...>& obj) {}
};

template <typename... Args>
ostream& operator<<(ostream& os, const std::tuple<Args...>& t) {
    os << "[";

    MyPrintTuple<0, sizeof...(Args), Args...>::MyPrint(os, t);
    return os << "]";
}

////////////////////////////////////////////example///6///////////////////////////////////////////////////////
#include <tuple>

template <typename...> class MyTuple {};

// template<> class MyTuple<>{};

template <typename Head, typename... Tail>
class MyTuple<Head, Tail...> : private MyTuple<Tail...> {
    using inherited = MyTuple<Tail...>;

  public:
    MyTuple() { ; }
    MyTuple(Head v, Tail... tail) : mHead(v), inherited(tail...) {}
    Head head() { return mHead; }
    inherited& tail() { return *this; }

  protected:
    Head mHead;
};

// template<typename Head,typename... Tail>
// ostream& operator<<(ostream &out,MyTuple<Head,Tail...>& obj)
// {
//     out<<obj.head()<<",";
//     operator<<(out,obj.tail());
//     return out;
// }
template <typename... Tail>
ostream& operator<<(ostream& out, MyTuple<Tail...>& obj) {
    out << obj.head() << ",";
    operator<<(out, obj.tail());
    return out;
}
template <typename...> ostream& operator<<(ostream& out, MyTuple<>& obj) {
    out << endl;
    return out;
}
////////////////////////////////////////////example///7///////////////////////////////////////////////////////

template <typename...> class VTuple {};

template <typename Head, typename... Tail> 
class VTuple<Head, Tail...> {
  public:
    using composited = VTuple<Tail...>;
    VTuple(){}
    VTuple(Head m, Tail... t):mhead(m),mtail(t...)
    {
        cout<<"head:"<<this<<"\t"<<m<<endl;
    }
    Head head()
    {
        return mhead;
    }
    composited& tail()
    {
        return mtail;
    }
protected:
  Head mhead;
  composited mtail; 
};

void testVariadicTemplate() {

    cout << "////////////////////////////////////////////example "
            "1///////////////////////////////////////////////////////"
         << endl;
    // print variadic templates
    print(1.0, 2, 3.3, 4.5, 6);

    cout << "////////////////////////////////////////////example "
            "2///////////////////////////////////////////////////////"
         << endl;

    int* pi = new int{5};
    myPrintf("%ld %ls %p %f\n", 15, "this is ace", pi, 3.45);

    cout << "////////////////////////////////////////////example "
            "3///////////////////////////////////////////////////////"
         << endl;

    cout << "max_element value3:" << vmax({57, 48, 60, 100, 20, 18}) << endl;

    cout << "////////////////////////////////////////////example "
            "4///////////////////////////////////////////////////////"
         << endl;

    cout << "max_element value4:" << ymaximum(57, 48, 60, 100, 20, 18) << endl;

    cout << "////////////////////////////////////////////example ""5///////////////////////////////////////////////////////"<< endl;

    cout << make_tuple(7.5, "hello", bitset<16>(377), 42) << endl;

    cout << "////////////////////////////////////////////example "
            "6///////////////////////////////////////////////////////"
         << endl;
    MyTuple<int, std::string, float> mt(10, "hello", 23.5);
    cout<<"sizeof(mt):"<<sizeof(mt)<<endl;
    cout << mt.head() << endl;
    cout << mt.tail().head() << endl;
    cout << mt.tail().tail().head() << endl;
    cout << "-----------------------------------" << endl;
    cout << "MyTuple<" << mt << ">" << endl;

     cout << "////////////////////////////////////////////example ""7///////////////////////////////////////////////////////"<< endl;
    VTuple<int, std::string, float> mt1(10, "hello", 23.5);
    cout<<"sizeof(mt):"<<sizeof(mt1)<<endl;
    cout << mt1.head() << endl;
    cout << mt1.tail().head() << endl;
    cout << mt1.tail().tail().head() << endl;
    cout << "-----------------------------------" << endl;
}